package com.yourname.projectname.config.interceptor;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yourname.projectname.util.JwtUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT 拦截器
 * 作用：验证请求中的 JWT 令牌，提取用户信息并设置到请求中
 *
 * 拦截规则：
 * 1. 跳过登录、注册等公开接口
 * 2. 拦截需要认证的 API 接口
 * 3. 验证 JWT 有效性（签名、过期时间）
 * 4. 将用户信息存入请求属性，供 Controller 使用
 */
@Component
public class JwtInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(JwtInterceptor.class);

    @Resource
    private ObjectMapper objectMapper;

    // 需要跳过的路径（公开接口）
    @Value("${jwt.excludePaths}")
    private String[] EXCLUDE_PATHS;

    /**
     * 在请求处理前执行
     *
     * @param request  当前请求
     * @param response 当前响应
     * @param handler  处理器对象
     * @return true 表示继续执行，false 表示中断
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1. 检查是否为需要跳过的路径
        if (isExcludedPath(request)) {
            return true; // 跳过认证
        }

        // 2. 从请求头获取 JWT 令牌
        String token = getTokenFromRequest(request);
        if (token == null) {
            sendErrorResponse(response, "未提供认证令牌", HttpStatus.UNAUTHORIZED);
            return false;
        }

        // 3. 验证 JWT 令牌
        Map<String, String> userInfo = JwtUtil.validateToken(token);
        if (userInfo == null) {
            sendErrorResponse(response, "无效或过期的令牌", HttpStatus.UNAUTHORIZED);
            return false;
        }

        // 4. 将用户信息存入请求属性，供后续使用
        request.setAttribute("currentUserPhone", userInfo.get("phone"));
        request.setAttribute("currentUserRole", userInfo.get("role"));

        // 5. 打印日志（调试用，毕业设计中可保留作为演示）
        System.out.println("[JWT 认证成功] 手机号: " + userInfo.get("phone") +
                ", 角色: " + userInfo.get("role") +
                ", 请求路径: " + request.getRequestURI());

        return true; // 继续执行
    }

    /**
     * 检查当前请求路径是否需要跳过认证
     */
    private boolean isExcludedPath(HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        for (String path : EXCLUDE_PATHS) {
            // 简单的路径匹配（毕业设计够用）
            if (path.endsWith("/**")) {
                String basePath = path.substring(0, path.length() - 3);
                if (requestURI.startsWith(basePath)) {
                    return true;
                }
            } else if (requestURI.equals(path)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 从请求头中提取 JWT 令牌
     * 格式：Authorization: Bearer <token>
     */
    private String getTokenFromRequest(HttpServletRequest request) {
        String authHeader = request.getHeader("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            return authHeader.substring(7); // 去掉 "Bearer " 前缀
        }
        return null;
    }

    /**
     * 发送 JSON 格式的错误响应
     */
    private void sendErrorResponse(HttpServletResponse response, String message, HttpStatus status) throws IOException {
        response.setStatus(status.value());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");

        Map<String, Object> errorResponse = new HashMap<>();
        errorResponse.put("code", status.value());
        errorResponse.put("message", message);
        errorResponse.put("timestamp", System.currentTimeMillis());

        response.getWriter().write(objectMapper.writeValueAsString(errorResponse));
    }
}